package org.wedding.center.pay.wxpay.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.gson.Gson;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.*;
import com.ijpay.wxpay.model.v3.*;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.wedding.center.entity.AmountInfo;
import org.wedding.center.entity.ApprovalInfo;
import org.wedding.center.entity.OrderInfo;
import org.wedding.center.entity.WxPay;
import org.wedding.center.pay.wxpay.config.WxPayV3Bean;
import org.wedding.center.service.AmountInfoService;
import org.wedding.center.service.ApprovalInfoService;
import org.wedding.center.service.OrderInfoService;
import org.wedding.center.service.WxPayService;
import org.wedding.enums.system.ResultCodeEnum;
import org.wedding.system.entity.UserInfo;
import org.wedding.system.service.IUserService;
import org.wedding.utils.CommonResult;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * <p>IJPay 让支付触手可及，封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
 *
 * <p>不依赖任何第三方 mvc 框架，仅仅作为工具使用简单快速完成支付模块的开发，可轻松嵌入到任何系统里。 </p>
 *
 * <p>IJPay 交流群: 723992875、864988890</p>
 *
 * <p>Node.js 版: <a href="https://gitee.com/javen205/TNWX">https://gitee.com/javen205/TNWX</a></p>
 *
 * <p>微信支付 v3 接口示例</p>
 *
 * @author Javen
 */
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
@RestController
@RequestMapping("/v3")
public class WxPayV3Controller {
    private final static int OK = 200;
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private WxPayV3Bean wxPayV3Bean;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private AmountInfoService amountInfoService;
    @Autowired
    private ApprovalInfoService approvalInfoService;
    @Autowired
    private IUserService userService;

    private static String serialNo;

    /**
     * 获取商户证书序列号
     *
     * @return
     */
    private String getSerialNumber() {
        // 如果序列号为空
        if (StrUtil.isEmpty(serialNo)) {
            // 获取证书
            X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getCertPath()));
            // 获取序列号并转换为大写
            serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
        }
        // 打印序列号
        System.out.println("serialNo:" + serialNo);
        // 返回序列号
        return serialNo;
    }

    /**
     * 下单并发起微信支付
     *
     * @param order
     * @return
     */
    @Operation(summary = "下单并发起微信支付")
    @RequestMapping("/jsApiPay")
    @ResponseBody
    public CommonResult jsApiPay(@RequestBody OrderInfo order) {
        try {
            if (ObjectUtil.isEmpty(order.getOrderAmount())) {
                return CommonResult.failed("订单金额不能为空！");
            }
            if (ObjectUtil.isEmpty(order.getPayDeposit())) {
                return CommonResult.failed("订单付款方式不能为空！");
            }
            // 创建微信支付订单
            order.setPayType("0");
//            OrderInfo orderInfo = orderInfoService.view(order.getId()).getData();
            OrderInfo orderInfo = orderInfoService.findByCode(order.getCode());
            if (ObjectUtil.isEmpty(orderInfo)) {
                CommonResult<OrderInfo> result = orderInfoService.add(order);
                if (result.getCode()!=(ResultCodeEnum.SUCCESS.getCode())) {
                    return result;
                }
                orderInfo =result.getData();
            }
            // 将 元 单位转化为 分
            String outTradeNo = order.getCode(); //订单编号
            int amount = orderInfo.getAmount().multiply(new BigDecimal(100)).intValue();
            if (StrUtil.isNotEmpty(order.getPayDeposit()) && "1".equals(order.getPayDeposit())) {
                if (ObjectUtil.isNotEmpty(orderInfo.getFinalAmount())) {
                    //尾款订单-使用尾款金额支付
                    amount = orderInfo.getFinalAmount().multiply(new BigDecimal(100)).intValue();
                    outTradeNo = outTradeNo+"_"+orderInfo.getWkcode();
                }
            }
            String openId = StpUtil.getSession().get("openId").toString();
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);

            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(wxPayV3Bean.getAppId())
                    .setMchid(wxPayV3Bean.getMchId())
                    .setDescription("支付")
                    .setOut_trade_no(outTradeNo)
                    .setTime_expire(timeExpire)
                    .setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
                    .setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
//                    .setAmount(new Amount().setTotal(amount))
                    .setAmount(new Amount().setTotal(1)) //todo 测试支付金额 1就是1分钱，100=1元
                    .setPayer(new Payer().setOpenid(openId));

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));

            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    BasePayApiEnum.JS_API_PAY.toString(),
                    wxPayV3Bean.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    JSONUtil.toJsonStr(unifiedOrderModel)
            );
            log.info("统一下单响应 {}", response);
            // 根据证书序列号查询对应的证书来验证签名结果-使用公钥模式验签
            boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
            log.info("verifySignature: {}", verifySignature);
            if (response.getStatus() == OK && verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                String prepayId = jsonObject.getStr("prepay_id");
                Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
                log.info("唤起支付参数:{}", map);
                //新增微信支付相关信息数据
                wxPayService.add(WxPay.builder()
                        .orderCode(outTradeNo)
                        .payStatus(orderInfo.getPayStatus())
                        .type("请求成功---->下单并发起微信支付")
                        .resData("response:" + JSONUtil.toJsonStr(response) + "\n orderInfo:" + JSONUtil.toJsonStr(orderInfo))
                        .repData(JSONUtil.toJsonStr(map))
                        .build());
                return CommonResult.success(JSONUtil.toJsonStr(map));
            }
            //新增微信支付相关信息数据
            wxPayService.add(WxPay.builder()
                    .orderCode(outTradeNo)
                    .payStatus(orderInfo.getPayStatus())
                    .type("请求失败---->下单并发起微信支付")
                    .resData(JSONUtil.toJsonStr(orderInfo))
                    .repData(JSONUtil.toJsonStr(response))
                    .build());
            return CommonResult.failed(JSONUtil.toJsonStr(response));
        } catch (Exception e) {
            log.error("系统异常", e);
            return CommonResult.failed(ResultCodeEnum.API_ERROR);
        }
    }

    /**
     * 微信支付回调
     *
     * @param request
     * @param response
     */
    @Operation(summary = "微信支付回调")
    @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    @ResponseBody
    @Transactional
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
                    wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
            log.info("支付通知明文 {}", plainText);
            Gson gson = new Gson();
            String userId = "";
            String userName = "";
            if (StrUtil.isNotEmpty(plainText)) {
                HashMap hashMap = gson.fromJson(plainText, HashMap.class);
                String orderNo = (String) hashMap.get("out_trade_no");
                //支付成功-更新订单信息
                OrderInfo orderInfo = this.processOrder(orderNo);
                if (ObjectUtil.isNotEmpty(orderInfo)) {
                    UserInfo userInfo = userService.view(orderInfo.getUserId()).getData();
                    if (ObjectUtil.isNotEmpty(userInfo)) {
                        userId = userInfo.getId();
                        userName = userInfo.getNickName();
                    }
                }
                System.out.println("微信notify_url 验证成功开始处理业务");
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
                //新增微信支付相关信息数据
                wxPayService.add(WxPay.builder()
                        .creator(userId)
                        .creatorName(userName)
                        .orderCode(orderNo)
                        .payStatus("1")
                        .type("请求成功---->微信支付回调")
                        .resData(result)
                        .repData(JSONUtil.toJsonStr(map))
                        .build());
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
                //新增微信支付相关信息数据
                wxPayService.add(WxPay.builder()
                        .creator(userId)
                        .creatorName(userName)
                        .orderCode(plainText)
                        .payStatus("1")
                        .type("请求失败---->微信支付回调签名错误")
                        .resData(result)
                        .repData(JSONUtil.toJsonStr(map))
                        .build());
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("系统异常", e);
        }
    }

    /**
     * 更新订单状态
     *
     * @param orderNo
     * @throws GeneralSecurityException
     */
    public OrderInfo processOrder(String orderNo) {
        try {
            log.info("处理订单");
            boolean isDeposit = false;
            if (orderNo.contains("WK")) {
                orderNo = orderNo.split("_")[0];
                isDeposit = true;
            }
            OrderInfo orderInfo = orderInfoService.findByCode(orderNo);
            if (ObjectUtil.isNotEmpty(orderInfo) && "1".equals(orderInfo.getStatus())  && ! isDeposit) {
                return null;
            }
            if (ObjectUtil.isNotEmpty(orderInfo) && "1".equals(orderInfo.getFinalStatus())  &&  isDeposit) {
                return null;
            }
            log.info("更新订单状态-----------开始");
            //更新订单状态
            OrderInfo data = orderInfoService.payStatus(orderNo, "1", isDeposit).getData();
            log.info("更新订单状态-----------成功");
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }


    /**
     * @param outTradeNo
     * @Author:zhaoyongke
     * @Description:前端 定时查询 关闭二维码
     * @Date: 2024/2/7 14:10
     */
    @RequestMapping("/query")
    @ResponseBody
    public String query(@RequestParam String outTradeNo) {
        try {
            Map<String, String> params = new HashMap<>(16);
            params.put("mchid", wxPayV3Bean.getMchId());

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(params));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.GET,
                    WxDomainEnum.CHINA.toString(),
                    String.format(BasePayApiEnum.ORDER_QUERY_BY_OUT_TRADE_NO.toString(), outTradeNo),
                    wxPayV3Bean.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    params,
                    AuthTypeEnum.RSA.getCode()
            );
            log.info("查询响应 {}", response);
            if (response.getStatus() == OK) {
                // 根据证书序列号查询对应的证书来验证签名结果
                boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
                log.info("verifySignature: {}", verifySignature);
                return response.getBody();
            }
            return JSONUtil.toJsonStr(response);
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
    }

    /**
     * 退款
     *
     */
    @PostMapping("/refund")
    @ResponseBody
    public CommonResult refund( @RequestBody OrderDTO  info) {

        String orderNo = info.getOrderNo();
        try {
            if (StrUtil.isEmpty(orderNo)) {
                return CommonResult.failed("商户退款单号不能为空");
            }
            log.warn("商户退款单号: {" + orderNo + "}");
            boolean isDeposit = false;
            if (orderNo.contains("WK-")) {
                orderNo = orderNo.replace("WK-", "");
                isDeposit = true;
            }
            OrderInfo orderInfo = orderInfoService.findByCode(orderNo);
            if (ObjectUtil.isNotEmpty(orderInfo) && "1".equals(orderInfo.getPayStatus())) {
                //取消订单
                long diff = DateUtil.between(DateUtil.parse(orderInfo.getCreateTime()), DateUtil.date(), DateUnit.MINUTE);
                if (diff < 60) {
                    if (StrUtil.isEmpty(orderNo)) {
                        return CommonResult.failed("商户退款单号不能为空");
                    }
                    int amount = orderInfo.getAmount().multiply(new BigDecimal(100)).intValue();
                    // 支付1小时内可以 取消订单并退款
                    List<RefundGoodsDetail> list = new ArrayList<>();
                    RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
                            .setMerchant_goods_id(orderNo)
                            .setGoods_name("取消订单")
//                    .setUnit_price(amount) //金额单位为 分
                            .setUnit_price(1) //金额单位为 分
                            .setRefund_amount(1)
                            .setRefund_quantity(1);
                    list.add(refundGoodsDetail);

                    RefundModel refundModel = new RefundModel()
                            .setOut_trade_no(orderNo)
                            .setOut_refund_no(orderNo)
                            .setReason("IJPay 测试退款")
                            .setNotify_url(wxPayV3Bean.getDomain().concat("/v3/refundNotify"))
                            .setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
                            .setGoods_detail(list);

                    log.warn("退款参数 {" + JSONUtil.toJsonStr(refundModel) + "}");
                    X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getCertPath()));
                    String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
                    IJPayHttpResponse response = WxPayApi.v3(
                            RequestMethodEnum.POST,
                            WxDomainEnum.CHINA.toString(),
                            BasePayApiEnum.REFUND.toString(),
                            wxPayV3Bean.getMchId(),
                            serialNo,
                            null,
                            wxPayV3Bean.getKeyPath(),
                            JSONUtil.toJsonStr(refundModel)
                    );
                    // 根据证书序列号查询对应的证书来验证签名结果
                    boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
                    log.warn("verifySignature: {" + verifySignature + "}");
                    log.warn("退款响应 {" + response + "}");
                    if (verifySignature) {
                        //更新订单状态
//                        orderInfoService.payStatus(orderNo, "3", isDeposit);
                        orderInfoService.updateOrderStatus(orderNo, "3");
                        //新增退款金额明细
//                        CommonResult commonResult = amountInfoService.add(AmountInfo.builder()
//                                .userId(orderInfo.getMerchantId())
//                                .userName(orderInfo.getMerchantName())
//                                .changeAmount(orderInfo.getAmount())
//                                .changeType("1")
//                                .changeDetails("取消订单并退款")
//                                .build());
//                        if (commonResult.getCode() != 0) {
//                            return commonResult;
//                        }
                        //新增微信支付相关信息数据
                        wxPayService.add(WxPay.builder()
                                .orderCode(orderNo)
                                .payStatus("2")
                                .type("请求成功---->微信支付退款回调")
                                .resData(JSONUtil.toJsonStr(refundModel))
                                .repData(response.getBody())
                                .build());
                        return CommonResult.success("退款成功");
                    } else {
                        return CommonResult.failed("退款失败-验签失败");
                    }
                } else {
                    if ("1".equals(orderInfo.getIsDeposit())) {
                        //全款订单-提交退款申请到商家
                        approvalInfoService.add(ApprovalInfo.builder()
                                .businessType("2")
                                .businessId(orderInfo.getCode())
                                .approver(orderInfo.getMerchantId())
                                .approverName(orderInfo.getMerchantName())
                                .build());
                        return CommonResult.success("退款申请提交成功");
                    } else {
                        //定金订单-直接取消成功
                        orderInfoService.payStatus(orderNo, "3", true);
                        orderInfoService.updateOrderStatus(orderNo, "3");
                        return CommonResult.success("退款成功");
                    }
                }
            } else {
                return CommonResult.failed("订单还未支付，不支持取消订单！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("取消订单退款失败");
        }
    }


    /**
     * 微信退款审批
     *
     * @param approvalInfo
     * @return
     */
    @RequestMapping(value = "/wxRefund", method = {RequestMethod.POST, RequestMethod.GET}, produces = "application/json; charset=UTF-8")
    @Transactional
    public CommonResult wxRefund(@RequestBody ApprovalInfo approvalInfo) {
        try {
            if ("2".equals(approvalInfo.getStatus())) {
                //审批不通过
                return approvalInfoService.updateEntity(approvalInfo);
            } else {

                String orderNo = approvalInfo.getBusinessId();
                if (StrUtil.isEmpty(orderNo)) {
                    return CommonResult.failed("商户退款单号不能为空");
                }
                boolean isDeposit = false;
                if (orderNo.contains("WK-")) {
                    orderNo = orderNo.replace("WK-", "");
                    isDeposit = true;
                }
                OrderInfo orderInfo = orderInfoService.findByCode(orderNo);
                int amount = orderInfo.getAmount().multiply(new BigDecimal(100)).intValue();
                // 支付1小时内可以 取消订单并退款
                List<RefundGoodsDetail> list = new ArrayList<>();
                RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
                        .setMerchant_goods_id(orderNo)
                        .setGoods_name("取消订单")
//                    .setUnit_price(amount) //金额单位为 分
                        .setUnit_price(1) //金额单位为 分
                        .setRefund_amount(1)
                        .setRefund_quantity(1);
                list.add(refundGoodsDetail);

                RefundModel refundModel = new RefundModel()
                        .setOut_trade_no(orderNo)
                        .setOut_refund_no(orderNo)
                        .setReason("IJPay 测试退款")
                        .setNotify_url(wxPayV3Bean.getDomain().concat("/v3/refundNotify"))
                        .setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
                        .setGoods_detail(list);

                log.warn("退款参数 {" + JSONUtil.toJsonStr(refundModel) + "}");
                X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getCertPath()));
                String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
                IJPayHttpResponse response = WxPayApi.v3(
                        RequestMethodEnum.POST,
                        WxDomainEnum.CHINA.toString(),
                        BasePayApiEnum.REFUND.toString(),
                        wxPayV3Bean.getMchId(),
                        serialNo,
                        null,
                        wxPayV3Bean.getKeyPath(),
                        JSONUtil.toJsonStr(refundModel)
                );
                // 根据证书序列号查询对应的证书来验证签名结果
                boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
                log.warn("verifySignature: {" + verifySignature + "}");
                log.warn("退款响应 {" + response + "}");
                if (response.getStatus() == OK && verifySignature) {
                    //新增微信支付相关信息数据
                    wxPayService.add(WxPay.builder()
                            .orderCode(orderNo)
                            .payStatus("2")
                            .type("请求成功---->提交微信支付退款审批申请")
                            .resData(JSONUtil.toJsonStr(refundModel))
                            .repData(response.getBody())
                            .build());
                    return CommonResult.success("退款成功");
                } else {
                    String message = JSONUtil.parseObj(response.getBody()).getStr("message");
                    return CommonResult.failed(message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 退款回调
     *
     * @param jsonData
     * @return
     * @throws Exception
     */
    @PostMapping("/refundNotify")
    @Transactional
    public Object refundNotifyResult(@RequestBody String jsonData) throws Exception {
        //转为map格式
        Map<String, String> jsonMap = JSONUtil.toBean(jsonData, Map.class);

        //退款成功后返回一个加密字段resource,以下为解密
        /**
         * 解密需要从resource参数中，获取到ciphertext，nonce，associated_data这三个参数进行解密
         */
        String resource = JSONUtil.toJsonStr(jsonMap.get("resource"));
        JSONObject object = JSONUtil.parseObj(resource);

        String ciphertext = String.valueOf(object.get("ciphertext"));
        String nonce = String.valueOf(object.get("nonce"));
        String associated_data = String.valueOf(object.get("associated_data"));

        String resultStr = decryptToString(associated_data.getBytes("UTF-8"), nonce.getBytes("UTF-8"), ciphertext);
        Map<String, String> reqInfo = JSONUtil.toBean(resultStr, Map.class);

        String refund_status = reqInfo.get("refund_status");//退款状态
        String orderNo = reqInfo.get("out_trade_no"); //订单号

        Map<String, Object> parm = new HashMap<>();
        if (!StrUtil.isEmpty(refund_status) && "SUCCESS".equals(refund_status)) {
            //你自己的业务
            //更新审批状态为已通过
            ApprovalInfo approvalInfo = approvalInfoService.findBybusinessIDAndType(orderNo, "2");
            if(approvalInfo!=null){
                approvalInfo.setStatus("1");
                approvalInfoService.updateById(approvalInfo);
            }
            boolean isDeposit = false;
            if (orderNo.contains("WK-")) {
                orderNo = orderNo.replace("WK-", "");
                isDeposit = true;
            }

            OrderInfo orderInfo = orderInfoService.findByCode(orderNo);
            //更新订单状态
            orderInfoService.payStatus(orderNo, "3", isDeposit);
            orderInfoService.updateOrderStatus(orderNo, "3");
            //新增退款金额明细
            CommonResult commonResult = amountInfoService.add(AmountInfo.builder()
                    .userId(orderInfo.getMerchantId())
                    .userName(orderInfo.getMerchantName())
                    .changeAmount(orderInfo.getAmount())
                    .changeType("1")
                    .changeDetails("取消订单并退款")
                    .build());
            if (commonResult.getCode() != 0) {
                return commonResult;
            }
            //新增微信支付相关信息数据
            wxPayService.add(WxPay.builder()
                    .orderCode(orderNo)
                    .payStatus("2")
                    .type("请求成功---->微信支付退款回调")
                    .resData(JSONUtil.toJsonStr(orderInfo))
                    .repData(resource)
                    .build());
            parm.put("code", "SUCCESS");
            parm.put("message", "成功");
        } else {
            parm.put("code", "FAIL");
            parm.put("message", "失败");
            throw new RuntimeException("退款失败");
        }
        return parm;  //返回给前端的参数
    }

    //退款回调  解密数据
    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            SecretKeySpec key = new SecretKeySpec(wxPayV3Bean.getApiKey3().getBytes(), "AES");//todo 这里的apiV3key是你的商户APIV3密钥
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce);//规定为128

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);

            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 退款
     *
     * @param transactionId
     * @param outTradeNo
     * @return
     */
    @RequestMapping("/refund1")
    @ResponseBody
    public String refund1(@RequestParam(required = false) String transactionId,
                          @RequestParam(required = false) String outTradeNo) {
        try {
            String outRefundNo = PayKit.generateStr();
            log.info("商户退款单号: {}", outRefundNo);

            List<RefundGoodsDetail> list = new ArrayList<>();
            RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
                    .setMerchant_goods_id("123")
                    .setGoods_name("IJPay 测试")
                    .setUnit_price(1)
                    .setRefund_amount(1)
                    .setRefund_quantity(1);
            list.add(refundGoodsDetail);

            RefundModel refundModel = new RefundModel()
                    .setOut_refund_no(outRefundNo)
                    .setReason("IJPay 测试退款")
                    .setNotify_url(wxPayV3Bean.getDomain().concat("/v3/refundNotify"))
                    .setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
                    .setGoods_detail(list);

            if (StrUtil.isNotEmpty(transactionId)) {
                refundModel.setTransaction_id(transactionId);
            }
            if (StrUtil.isNotEmpty(outTradeNo)) {
                refundModel.setOut_trade_no(outTradeNo);
            }
            log.info("退款参数 {}", JSONUtil.toJsonStr(refundModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    BasePayApiEnum.REFUND.toString(),
                    wxPayV3Bean.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    JSONUtil.toJsonStr(refundModel)
            );
            // 根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayV3Bean.getPlatformCertPath());
            log.info("verifySignature: {}", verifySignature);
            log.info("退款响应 {}", response);

            if (verifySignature) {
                return response.getBody();
            }
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
        return null;
    }


}
